package net.linku.exception;

import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import net.linku.exception.enums.ExceptionEnum;
import net.linku.model.R;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.server.ResponseStatusException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.UnexpectedTypeException;
import javax.validation.ValidationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
@Component("globalExceptionHandler")
public class GlobalExceptionHandler {

    /**
     * 处理 SQL 约束违规的异常
     *
     * @param e SQLIntegrityConstraintViolationException
     * @return R 响应结果
     */
    @ExceptionHandler(value = {SQLIntegrityConstraintViolationException.class, DataIntegrityViolationException.class})
    public R sqlIntegrityConstraintViolationExceptionHandler(Exception e) {
        log.error("数据库约束违规！原因是:", e);
        return R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR.getResultCode(), "数据库约束违规！" + e.getMessage());
    }

    /**
     * 处理自定义的业务异常
     *
     * @param req HttpServletRequest
     * @param e   LinkUException
     * @return R 响应结果
     */
    @ExceptionHandler(value = LinkUException.class)
    public R linkUExceptionHandler(HttpServletRequest req, LinkUException e) {
        log.error("发生业务异常！原因是：{}", e.getErrorMsg(), e);
        return R.fail(e.getErrorCode(), e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     *
     * @param req HttpServletRequest
     * @param e   NullPointerException
     * @return R 响应结果
     */
    @ExceptionHandler(value = NullPointerException.class)
    public R nullPointerExceptionHandler(HttpServletRequest req, NullPointerException e) {
        log.error("发生空指针异常！原因是:", e);
        return R.fail(ExceptionEnum.BODY_NOT_MATCH.getResultCode(), "空指针异常，请联系管理员");
    }

    /**
     * 处理内部API调用的异常
     *
     * @param e ApiException对象
     * @return 统一返回值对象
     */
    @ExceptionHandler(value = ApiException.class)
    public R handleApiException(ApiException e) {
        if (e.getErrorCode() != null) {
            return R.fail(e.getErrorCode());
        }
        return R.fail(e.getMessage());
    }

    /**
     * 处理方法参数校验失败的异常
     *
     * @param e MethodArgumentNotValidException
     * @return R 响应结果
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        return processBindingResult(e.getBindingResult());
    }

    /**
     * 处理参数绑定失败的异常
     *
     * @param e BindException
     * @return R 响应结果
     */
    @ExceptionHandler(value = BindException.class)
    public R bindExceptionHandler(BindException e) {
        return processBindingResult(e.getBindingResult());
    }

    /**
     * 处理缺少请求参数的异常
     *
     * @param e MissingServletRequestParameterException
     * @return R 响应结果
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public R missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        return R.fail("缺少请求参数: " + e.getParameterName());
    }

    /**
     * 处理请求方法不支持的异常
     *
     * @param e HttpRequestMethodNotSupportedException
     * @return R 响应结果
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public R httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        return R.fail("不支持的请求方法: " + e.getMethod());
    }

    /**
     * 处理消息不可读的异常
     *
     * @param e HttpMessageNotReadableException
     * @return R 响应结果
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public R httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        return R.fail("消息不可读");
    }

    /**
     * 处理权限不足的异常
     *
     * @param e AccessDeniedException
     * @return R 响应结果
     */
    @ExceptionHandler(value = AccessDeniedException.class)
    public R accessDeniedExceptionHandler(AccessDeniedException e) {
        return R.fail(HttpStatus.FORBIDDEN.value(), "权限不足");
    }

    /**
     * 处理参数校验失败的异常
     *
     * @param e ConstraintViolationException
     * @return R 响应结果
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public R constraintViolationExceptionHandler(ConstraintViolationException e) {
        return R.fail("参数校验失败: " + e.getMessage());
    }

    /**
     * 处理验证失败的异常
     *
     * @param e ValidationException
     * @return R 响应结果
     */
    @ExceptionHandler(value = ValidationException.class)
    public R validationExceptionHandler(ValidationException e) {
        String message = "验证失败";
        if (e instanceof ConstraintViolationException) {
            ConstraintViolationException constraintViolationException = (ConstraintViolationException) e;
            for (ConstraintViolation<?> violation : constraintViolationException.getConstraintViolations()) {
                String fieldName = violation.getPropertyPath().toString();
                message = fieldName + " 字段必填，请检查是否为空";
                break; // 只取第一个错误信息
            }
        } else if (e instanceof UnexpectedTypeException) {
            String fieldName = extractFieldNameFromMessage(e.getMessage());
            message = fieldName != null ? fieldName + " 字段类型不匹配，可能不支持该验证类型。" : "验证失败: 不支持的验证类型，可能是字段类型和验证注解不匹配。";
        } else {
            message = e.getMessage();
        }
        return R.fail(message);
    }

    private String extractFieldNameFromMessage(String message) {
        // 使用正则表达式或字符串处理提取字段名
        // 这里假设消息格式为 "属性名...的类型不支持"
        Pattern pattern = Pattern.compile("(?<=字段\\s)[^\\s]+");
        Matcher matcher = pattern.matcher(message);
        return matcher.find() ? matcher.group() : null;
    }

    /**
     * 处理 FeignClient 404 错误的异常
     *
     * @param e FeignException
     * @return 统一返回值对象
     */
    @ExceptionHandler(value = FeignException.class)
    public R handleFeignException(FeignException e) {
        // 提取报错信息中的用户名错误信息
        String message = extractUsernameErrorMessage(e.getMessage());
        return R.fail(HttpStatus.NOT_FOUND.value(), "Feign 调用失败：" + message);
    }

    /**
     * 处理 FeignClient 401 错误的异常
     *
     * @param e ResponseStatusException对象
     * @return 统一返回值对象
     */
    @ExceptionHandler(value = ResponseStatusException.class)
    public R handleResponseStatusException(ResponseStatusException e) {
        if (e.getStatus() == HttpStatus.UNAUTHORIZED) {
            return R.fail("认证失败：" + e.getReason());
        }
        return R.fail("发生了一个错误：" + e.getReason());
    }

    /**
     * 处理 Redis 连接失败的异常
     *
     * @param e RedisConnectionFailureException
     * @return R 响应结果
     */
    @ExceptionHandler(value = RedisConnectionFailureException.class)
    public R redisConnectionFailureExceptionHandler(RedisConnectionFailureException e) {
        log.error("Redis 连接失败！原因是:", e);
        return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Redis 连接失败，请检查服务状态");
    }

    /**
     * 处理 JDBC 连接失败的异常
     *
     * @param e CannotGetJdbcConnectionException
     * @return R 响应结果
     */
    @ExceptionHandler(value = CannotGetJdbcConnectionException.class)
    public R cannotGetJdbcConnectionExceptionHandler(CannotGetJdbcConnectionException e) {
        log.error("JDBC 连接失败！原因是:", e);
        return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), "数据库连接失败，请检查服务状态");
    }

    /**
     * 处理 SQL 语法错误的异常
     *
     * @param e SQLSyntaxErrorException
     * @return R 响应结果
     */
    @ExceptionHandler(value = SQLSyntaxErrorException.class)
    public R sqlSyntaxErrorExceptionHandler(SQLSyntaxErrorException e) {
        log.error("SQL 语法错误！原因是:", e);
        return R.fail("SQL 语法错误: " + e.getMessage());
    }

    /**
     * 处理 IllegalArgumentException 的异常
     *
     * @param e IllegalArgumentException
     * @return R 响应结果
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    public R illegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("发生参数异常！原因是:", e);
        return R.fail("参数异常: " + e.getMessage());
    }

    /**
     * 处理其他异常
     *
     * @param e Exception
     * @return R 响应结果
     */
    @ExceptionHandler(value = Exception.class)
    public R exceptionHandler(Exception e) {
        log.error("发生未知异常！原因是:", e);
        return R.fail(ExceptionEnum.INTERNAL_SERVER_ERROR.getResultCode(), "服务器内部错误，请联系管理员");
    }

    /**
     * 处理绑定结果的辅助方法
     *
     * @param bindingResult 绑定结果
     * @return R 响应结果
     */
    private R processBindingResult(BindingResult bindingResult) {
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMessage.append(fieldError.getField()).append(" ").append(fieldError.getDefaultMessage()).append("; ");
        }
        return R.fail("参数校验失败: " + errorMessage.toString());
    }

    /**
     * 提取用户名错误信息的辅助方法
     *
     * @param message 错误信息
     * @return 用户名错误信息
     */
    private String extractUsernameErrorMessage(String message) {
        // 假设用户名错误信息的格式为 "User '用户名' not found"
        Pattern pattern = Pattern.compile("User '(.*?)' not found");
        Matcher matcher = pattern.matcher(message);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return "用户未找到";
    }
}
